// Copyright (c) Microsoft Corporation. All rights reserved.

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Text;
using System.Web;

using Microsoft.TeamFoundation.Migration.Toolkit;
using Microsoft.TeamFoundation.Migration.Toolkit.Wit;

namespace Microsoft.TeamFoundation.Migration.WorkItemTracking.Wss
{
    internal sealed class WssMigrationFileAttachment: IMigrationFileAttachment
    {
        private string m_name;                  // File name
        private string m_url;                   // Url of the attachment
        private string m_tempFileName;          // Temp file name for the file
        private FileInfo m_fileInfo;            // File info

        /// <summary>
        /// Returns the attachment Url.
        /// </summary>
        public string Url { get { return m_url; } }


        #region IMigrationFileAttachment Members

        /// <summary>
        /// Returns the name of the file.
        /// </summary>
        public string Name { get { return m_name; } }

        /// <summary>
        /// Returns the file size.
        /// </summary>
        public long Length { get { return m_fileInfo.Length; } }

        /// <summary>
        /// Returns the date/time the file was created.
        /// Wss does not give us this date so we are using the task's creation date.
        /// </summary>
        public DateTime UtcCreationDate { get { return m_fileInfo.CreationTimeUtc; } }

        /// <summary>
        /// Returns the date/time the file was last updated.
        /// Wss does not give us this date so we are using the task's modified date.
        /// </summary>
        public DateTime UtcLastWriteDate { get { return m_fileInfo.LastWriteTimeUtc; } }

        /// <summary>
        /// Returns any comment about the file.
        /// </summary>
        public string Comment { get { return string.Empty; } }

        /// <summary>
        /// Gets the contents of the file when needed for migration.
        /// </summary>
        /// <returns>Contents of the file.</returns>
        public Stream GetFileContents()
        {
            // Warning!!! This method returns a stream which will delete underlying temporary
            // file when closed. This is OK because the migration toolkit calls this method
            // only once.
            return new FileStream(
                m_tempFileName, 
                FileMode.Open, 
                FileAccess.Read, 
                FileShare.None, 
                4096, 
                FileOptions.DeleteOnClose | FileOptions.SequentialScan);
        }

        #endregion

        #region Constructors

        /// <summary>
        /// Constructor.
        /// </summary>
        /// <param name="task">Wss Task it is attached to</param>
        /// <param name="url">Url of the attachment</param>
        /// <param name="tempDir">Path for temp dir</param>
        internal WssMigrationFileAttachment(WssTask task, string url, string tempDir)
        {
            m_url = url;
            m_name = Path.GetFileName(url);
            m_tempFileName = DownloadFile(url, tempDir);
            m_fileInfo = new FileInfo(m_tempFileName);
        }

        #endregion

        #region Private Functions

        /// <summary>
        /// Downloads a file specified in the URL.
        /// </summary>
        /// <param name="url">URL of the file</param>
        /// <param name="tempDir">Directory to store temporary files</param>
        /// <returns>Name of the temporary file</returns>
        private string DownloadFile(string url, string tempDir)
        {
            string fileName = Path.Combine(tempDir, Guid.NewGuid().ToString());

            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.Method = "GET";
            request.Credentials = CredentialCache.DefaultNetworkCredentials;

            using (HttpWebResponse response = (HttpWebResponse)request.GetResponse())
            {
                if (response.StatusCode != HttpStatusCode.OK)
                {
                    string msg = string.Format(Resources.Culture, Resources.ErrorBadHttpResponse, response.StatusCode.ToString());
                    throw new WssStoreException(msg);
                }

                // Copy result to localFile stream
                using (Stream responseStream = response.GetResponseStream())
                {
                    byte[] buffer = new byte[1024];
                    int bytesRead;

                    // Create the new file then stream into it
                    using (Stream localFile = new FileStream(fileName, FileMode.CreateNew, FileAccess.Write))
                    {
                        while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            localFile.Write(buffer, 0, bytesRead);
                        }
                    }
                }
            }
            return fileName;
        }

        #endregion

    }
}
